import { createBot } from "mineflayer";
import { pathfinder, Movements, goals } from "mineflayer-pathfinder";
import minecraftData from "minecraft-data";
import { program } from "commander";
import dotenv from "dotenv";
import { Block } from "prismarine-block";
import { chatDispatch, Command } from "./dispatch";

const { GoalNear, GoalBlock } = goals;

program
    .argument("<username>")
    .argument("[password]")
    .option("-e, --env <file>", "specify .env file")
    .action(main)
    .parse(process.argv);

function main(username: string, password: string | undefined, options: { env?: string }) {
    dotenv.config({ path: options.env });

    const bot = createBot({
        host: process.env.HOST,
        port: process.env.PORT === undefined ? undefined : parseInt(process.env.PORT),
        username,
        password,
        version: process.env.VERSION,
    });

    bot.loadPlugin(pathfinder);

    const mcData = minecraftData(bot.version);

    const move = new Movements(bot, mcData);
    move.canDig = false;
    move.allow1by1towers = false;
    bot.pathfinder.setMovements(move);

    chatDispatch(bot, [
        new Command("come", player => {
            const target = player?.entity;
            if (!target) {
                bot.chat("I don't see you!");
                return;
            }

            const p = target.position;
            bot.pathfinder.setGoal(new GoalNear(p.x, p.y, p.z, 1));
        }),
        new Command(/^enter the (.+)$/, "enter the <block>", (_, match) => {
            const blockName = match[1];
            const blockType = mcData.blocksByName[blockName];
            if (blockType === undefined) {
                bot.chat(`I don't know the block ${blockName}!`);
                return;
            }

            let block = bot.findBlock({ matching: blockType.id, maxDistance: 32 });
            if (!block) {
                bot.chat(`I don't see a ${blockName} nearby!`);
                return;
            }

            if (blockType.boundingBox === "empty") {
                let down: Block | null;
                while (true) {
                    down = bot.blockAt(block.position.offset(0, -1, 0));
                    if (!(down && down.type === blockType.id)) break;
                    block = down;
                }
            }

            const p = block.position;
            bot.pathfinder.setGoal(new GoalBlock(p.x, p.y, p.z));
        })
    ]);

    bot.on("kicked", console.log);
    bot.on("error", console.log);
}
